/**
 * <p>Title: CNPEC 单点登陆主控制类 </p>
 * <p>Description: IMS</p>
 * <p>Copyright: Copyright (c) 2009</p>
 * <p>Company: CNPEC</p>
 */
package com.mes.cloud.domain.DefaultClient;

import com.mes.cloud.domain.Encryptor.AESCryption;
import com.mes.cloud.domain.Interface.IClient;
import com.mes.cloud.domain.config.DomainAutoConfiguration;
import com.mes.cloud.domain.helpers.UrlHelper;
import com.mes.cloud.domain.util.DateUtils;
import com.mes.cloud.domain.util.UtilTool;
import com.sun.jndi.toolkit.url.Uri;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 单点登陆主控制类
 *
 * @author yang yi
 * @version 1.0 $Id: AppClient.java,v 1.0 2009/07/20$
 */
public class AppClient implements IClient {
    private String requestAddress = null;// 认证服务器登录地址
    private String key = null;// 密码
    private String aseIV = null;// 向量
    private String siteID = null;// 子系统ID
    private String loginType = null;// 登录方式
    private int intTimeOut = 60;// 超时时间间隔（秒）

    private int requestPort;// 用户请求端口号
    private String extranetRequest = null;// 外网承包商请求端口号列表
    private String siteHemePage = null;// 当前系统登录请求页面

    private HttpServletRequest request = null;// 客户端请求

    private HttpServletResponse response = null;// 客户端响应

    private SsoAuthentication ssoAuthentication = null;// cookies读取类

    private String userIdBylogin = "";// ims控制中心返回的用户id
    private String loginId = "";

    /**
     * 构造函数
     *
     * @param request  客户端请求
     * @param response 客户端响应
     */
    public AppClient(HttpServletRequest request, HttpServletResponse response, DomainAutoConfiguration domainConfig) {
        this.request = request;
        this.response = response;
        requestAddress = domainConfig.getRequestAddress();
        key = domainConfig.getKey();
        aseIV = domainConfig.getAseIV();
        siteID = domainConfig.getSiteID();
        loginType = domainConfig.getLoginType();
        requestPort = request.getServerPort();
        extranetRequest = domainConfig.getExtranetRequest();
        siteHemePage = domainConfig.getSiteHemePage();
        intTimeOut = domainConfig.getIntTimeOut();
        ssoAuthentication = new SsoAuthentication(siteID, request, response);
    }

    /**
     * 系统登录 验证失败返回值为空，否则返回userid return ims控制中心返回的用户id
     */
    public String Login() {
        // 取得加密字符串
        String signtext = "";
        if (request.getParameter("signtext") != null && !"".equals(request.getParameter("signtext"))) {
            signtext = request.getParameter("signtext");
        } else {
            signtext = (String) request.getAttribute("signtext");
        }
        // 判断是否返回参数，带参数表示是从验证中心请求过来，否则是由用户自己发起的请求
        if (signtext == null || "".equals(signtext)) {
            try {
                this.TryLogin("");// 请求登录
            } catch (IOException e) {
                e.printStackTrace();
                return "";
            }
        }
        //// *********************从认证服务器请求后返回处理**************
        if (!this.Resolve())// 验证是否从认证服务器返回的Url
        {
            // 验证失败
            return "";
        }
        // ***************************************************************
        return userIdBylogin;
    }

    /**
     * 系统登录 验证失败返回值为空，否则返回userid return ims控制中心返回的用户id
     */
    public String LoginByRequestUrl(String siteUrl) {
        // 取得加密字符串

        String signtext = "";
        if (request.getParameter("signtext") != null && !"".equals(request.getParameter("signtext"))) {
            signtext = request.getParameter("signtext");
        } else {
            signtext = (String) request.getAttribute("signtext");
        }
        // 判断是否返回参数，带参数表示是从验证中心请求过来，否则是由用户自己发启的请求
        if (signtext == null || "".equals(signtext)) {
            try {
                this.TryLogin(siteUrl);// 请求登录
            } catch (IOException e) {
                e.printStackTrace();
                return "";
            }
        }
        //// *********************从认证服务器请求后返回处理**************
        if (!this.Resolve())// 验证是否从认证服务器返回的Url
        {
            // 验证失败
            return "";
        }
        // ***************************************************************
        return userIdBylogin;
    }

    public String getLoginId() {
        // 取得加密字符串
        String signtext = "";
        if (request.getParameter("signtext") != null && !"".equals(request.getParameter("signtext"))) {
            signtext = request.getParameter("signtext");
        } else {
            signtext = (String) request.getAttribute("signtext");
        }
        // 判断是否返回参数，带参数表示是从验证中心请求过来，否则是由用户自己发启的请求
        if (signtext == null || "".equals(signtext)) {
            String userId = ""; // 用户id
            if (ssoAuthentication.IsLogin()) {// 如果已经登录过，则取得保存在本地的cookise里的值
                userId = ssoAuthentication.getIuserId();// 取得已登录过cookise的值
                loginId = userId;
            }
        }
        return loginId;
    }

    /**
     * 从认证中心登录
     */
    private void TryLogin(String siteUrl) throws IOException {
        // 生成默认请求
        // LoginRequest loginRequest = new LoginRequest();
        // 生成36位随机码
        String identity = UtilTool.getRandomUUID();
        // 生成当前请求的时间，格式为：yyyy-MM-dd hh:mm:ss
        String timpStamp = DateUtils.getNowDateStr(0);
        // loginRequest.getTimeStamp();
        // 用户id
        String userId = "";
        // 工程码
        String projectCode = "";

        String ynDomianUser = "";
        // 如果已经登录过，则取得保存在本地的cookise里的值

        if (ssoAuthentication.IsLogin()) {
            // 取得已登录过cookise的值

            identity = ssoAuthentication.getIdentity();
            userId = ssoAuthentication.getIuserId();
            projectCode = ssoAuthentication.getProjectCode();
            ynDomianUser = ssoAuthentication.getYnDomainUser();
        }
        // 请求ip
        String terminalIp = request.getRemoteAddr();
        // 加密前的源数据,格式：子系统ID+用户ID+时间戳+标识+IP
        String encryptSource = this.siteID + "|" + userId + "|" + timpStamp + "|" + identity + "|" + terminalIp;
        // 加密后的数据
        String signText = AESCryption.encrypt(encryptSource, this.key, this.aseIV);
        // 认证服务器登录地址
        String requestAddress = this.requestAddress;
        // [Y，N]代表是否承包商外网请求
        String isContractorRequest = "N";
        // 通过用户请求链接地址的端口验证是否承包商外网请求
        if (this.isExtranetRequest()) {
            requestAddress = this.GenExtranetRequestAddress();
            isContractorRequest = "Y";
        }
        // 提交给验证中心的请求url
        StringBuffer url = new StringBuffer(requestAddress);
        UrlHelper.addParam(url, "siteid", this.siteID);
        UrlHelper.addParam(url, "signtext", signText);
        UrlHelper.addParam(url, "prjtcd", projectCode);
        UrlHelper.addParam(url, "logintype", this.loginType);
        // 第一个参数 代表请求类型 I为登录，第二个参数[N]代表是否承包商外网请求

        UrlHelper.addParam(url, "requesttype", "I" + isContractorRequest);
        UrlHelper.addParam(url, "requestport", new Integer(this.requestPort).toString());// 请求端口号
        if (siteUrl == null || "".equals(siteUrl)) {
            if (this.siteHemePage != null && !"".equals(this.siteHemePage)) {
                // 当前系统登录请求页面,认证服务器登录成功后返回至些URL.
                UrlHelper.addParam(url, "sitehomepage", this.siteHemePage);
            } else {
                UrlHelper.addParam(url, "sitehomepage", "");
            }
        } else {
            UrlHelper.addParam(url, "sitehomepage", siteUrl);
        }

        // 是否域用户

        UrlHelper.addParam(url, "ynduser", ynDomianUser);

        if (StringUtils.isNotEmpty(request.getParameter("targetpage"))) {
            UrlHelper.addParam(url, "targetpage", request.getParameter("targetpage"));
        }

        // 注消原身份标据

        ssoAuthentication.SignOut();

        // 跳转至认证服务器
        response.sendRedirect(url.toString());

    }

    /**
     * 通过用户请求链接地址的端口验证否承包商外网请求
     *
     * @return 如果为承包商外网请求返回true, 否则返回false
     */
    private boolean isExtranetRequest() {
        if (extranetRequest != null && !"".equals(extranetRequest)) {
            // 从配置文件中读取承包商端口清单

            String[] list = extranetRequest.split(";");
            // 如果当前用户请求的端口在清单中存在，则说明外部承包商请求 返回true
            for (int i = 0; i < list.length; i++) {

                if (list[i].equals(new Integer(this.requestPort).toString())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 生成请求外网请求认证中心地址URL. 主要用于承包商请求需跳转要相同的端口的认证中心网站的请求地址
     *
     * @return 返回请求外网请求认证中心地址URL
     */
    private String GenExtranetRequestAddress() {
        String requestAddress = this.requestAddress;

        Uri uri = null;
        try {
            uri = new Uri(this.requestAddress);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        // 外网请求认证中心地址URL的端口与内网不同，与xml配置进行替换
        requestAddress = "http://" + uri.getHost() + ":" + this.requestPort + uri.getPath();

        return requestAddress;
    }

    /**
     * 验证并处理从认证中心返回的URL 主要用于承包商请求需跳转要相同的端口的认证中心网站的请求地址
     *
     * @return 是否验证成功, true成功，false失败
     */
    private boolean Resolve() {
        // 解密后的用户id
        String userId = "";
        // 解密后的时间
        String timestamp = "";
        // 解密后的36位随机数
        String identity = "";
        // 解密后的IP
        String terminalIp = "";

        // 解密前的字符串

        String singText = "";
        if (request.getParameter("signtext") != null && !"".equals(request.getParameter("signtext"))) {
            singText = request.getParameter("signtext");
        } else {
            singText = (String) request.getAttribute("signtext");
        }
        // 获得工程代码
        String projectCode = "";
        if (request.getParameter("prjtcd") != null && !"".equals(request.getParameter("prjtcd"))) {
            projectCode = request.getParameter("prjtcd");
        } else {
            projectCode = (String) request.getAttribute("prjtcd");
        }
        // 获得是是否承包商外网请求
        String sIsDomainUser = "";
        if (request.getParameter("ynduser") != null && !"".equals(request.getParameter("ynduser"))) {
            sIsDomainUser = request.getParameter("ynduser");
        } else {
            sIsDomainUser = (String) request.getAttribute("ynduser");
        }
        if (!"Y".equals(sIsDomainUser)) {
            sIsDomainUser = "N";
        }
        // 从认证中心过来的signtext不能为空
        if (singText == null) {
            userId = "数据被非法篡改";
            return false;
        }

        try {
            // 数据解密
            String decryptSigntext = AESCryption.decrypt(singText, this.key, this.aseIV);
            // 以'|'分割解密后的数据
            String[] arrResposne = decryptSigntext.split("\\|");
            userId = arrResposne[0];
            timestamp = arrResposne[1];
            identity = arrResposne[2];
            terminalIp = arrResposne[3];
        } catch (Exception e) {
            userId = "数据被非法篡改";
            return false;
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 验证IP的合法性

        if (this.siteHemePage == null && "".equals(siteHemePage) && !terminalIp.equals(ip))// ??????
        {
            userId = "数据被非法篡改";
            return false;
        }

        // 超时验证
        if (DateUtils.getSubtractDate(timestamp, "") > this.intTimeOut) {
            userId = "请求超时";
            return false;
        }
        // 返回登陆后用户id
        this.userIdBylogin = userId;

        // 保存Cookie信息
        ssoAuthentication.SetAuthCookie(identity, userId, projectCode, sIsDomainUser);
        return true;
    }

    /**
     * 切换系统. 用于在不同子系统之间切换时调用此方法
     *
     * @param projectCode 工程代码
     * @param targeSiteId 目标系统id
     * @return 返回切换系统地址URL
     */
    public void ChangeToSite(String projectCode, String targeSiteId) throws Exception {
        this.ChangeToSite(projectCode, targeSiteId, null);
    }

    /**
     * 切换系统. 用于在不同子系统之间切换时调用此方法
     *
     * @param projectCode 工程代码
     * @param targeSiteId 目标系统ID
     * @param targetPage  目标页面
     * @return 返回切换系统地址URL
     */
    public void ChangeToSite(String projectCode, String targeSiteId, String targetPage) throws Exception {
        String ssoTicket = ssoAuthentication.getIdentity();
        String userId = ssoAuthentication.getIuserId();
        String sYnDomianUser = ssoAuthentication.getYnDomainUser();
        if (projectCode == null || "".equals(projectCode)) {
            throw new Exception("工程代码不能为空");
        }
        if (targeSiteId == null || "".equals(targeSiteId)) {
            throw new Exception("子系统代码不能为空");
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeStamp = dateFormat.format(new Date());
        String terminalIp = request.getRemoteAddr();
        String encryptSource = this.siteID + "|" + userId + "|" + timeStamp + "|" + ssoTicket + "|" + terminalIp;// 子系统ID+用户ID+时间戳+标识+IP
        String signText = AESCryption.encrypt(encryptSource, this.key, this.aseIV);

        String requestAddress = this.requestAddress;

        // 外网请求
        String sIsContractorRequest = "N";
        if (this.isExtranetRequest()) {
            requestAddress = this.GenExtranetRequestAddress();
            sIsContractorRequest = "Y";
        }

        StringBuffer sbUrl = new StringBuffer(requestAddress);
        UrlHelper.addParam(sbUrl, "siteid", this.siteID);
        UrlHelper.addParam(sbUrl, "signtext", signText);
        UrlHelper.addParam(sbUrl, "targetsiteid", targeSiteId);
        UrlHelper.addParam(sbUrl, "prjtcd", projectCode != null ? projectCode : "");
        UrlHelper.addParam(sbUrl, "targetpage", targetPage != null ? targetPage : "");
        // CNN第一个参数 代表请求类型 C为系统切换; 第二个N代表内网请求
        UrlHelper.addParam(sbUrl, "requesttype", "C" + sIsContractorRequest);
        UrlHelper.addParam(sbUrl, "requestport", new Integer(this.requestPort).toString());// 请求端口号

        UrlHelper.addParam(sbUrl, "ynduser", sYnDomianUser);// 是否域用户

        response.sendRedirect(sbUrl.toString());
    }

    /**
     * 系统登出(或叫切换用户) 跳转至认证中心登录页面
     */
    public void LogOut() throws IOException {
        // 从cookies中取得上一次登陆的信息
        String identity = ssoAuthentication.getIdentity();
        String userId = ssoAuthentication.getIuserId();
        String projectCode = ssoAuthentication.getProjectCode();
        String ynDomianUser = ssoAuthentication.getYnDomainUser();
        // 得到当前时间，格式：yyyy-MM-dd HH:mm:ss
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeStamp = dateFormat.format(new Date());
        // 获得请求的ip
        String terminalIp = request.getRemoteAddr();
        // 组合加密字符串,格式：子系统ID+用户ID+时间戳+标识+IP
        String encryptSource = this.siteID + "|" + userId + "|" + timeStamp + "|" + identity + "|" + terminalIp;
        // 字符串加密

        String signText = AESCryption.encrypt(encryptSource, this.key, this.aseIV);
        String requestAddress = this.requestAddress;

        // 是否为承包商外网请求
        String sIsContractorRequest = "N";
        if (this.isExtranetRequest()) {
            requestAddress = this.GenExtranetRequestAddress();
            sIsContractorRequest = "Y";
        }

        // 跳转到验证中心的url
        StringBuffer url = new StringBuffer(requestAddress);
        UrlHelper.addParam(url, "siteid", this.siteID);
        UrlHelper.addParam(url, "signtext", signText);
        UrlHelper.addParam(url, "prjtcd", projectCode);
        UrlHelper.addParam(url, "logintype", "");
        // 第一个参数 代表请求类型 O为登出系统, 第二个参数[N]代表是否承包商外网请求

        UrlHelper.addParam(url, "requesttype", "O" + sIsContractorRequest);
        UrlHelper.addParam(url, "requestport", new Integer(this.requestPort).toString());// 请求端口号

        if (this.siteHemePage != null && !"".equals(this.siteHemePage)) {
            // 当前系统登录请求页面,认证服务器登录成功后返回至些URL.
            UrlHelper.addParam(url, "sitehomepage", this.siteHemePage);
        } else {
            UrlHelper.addParam(url, "sitehomepage", "");
        }
        // 是否域用户

        UrlHelper.addParam(url, "ynduser", ynDomianUser);
        // 跳转至认证服务器
        response.sendRedirect(url.toString());
    }

    /**
     * 登录请求
     */
    public void LoignRequest() {
        try {
            this.TryLogin("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setSiteHemePage(String siteHemePage) {
        this.siteHemePage = "http://" + request.getServerName() + ":7001" + siteHemePage;
    }

    public void setLoginId(String loginId) {
        this.loginId = loginId;
    }
}
